package timing.ukulele.flow.controller;

import timing.ukulele.flow.service.CustomTaskRuntime;
import timing.ukulele.flow.service.FlowUserInfoService;
import timing.ukulele.flow.service.OperateTaskService;
import timing.ukulele.flow.util.ActivitiUtil;
import timing.ukulele.flow.util.ProcessHistoryManager;
import timing.ukulele.flow.util.ProcessInstanceManager;
import timing.ukulele.common.ResponseResult;
import timing.ukulele.flow.exception.NoUserException;
import timing.ukulele.flow.vo.TaskVO;
import timing.ukulele.flow.vo.UserVO;
import de.odysseus.el.ExpressionFactoryImpl;
import de.odysseus.el.util.SimpleContext;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.persistence.deploy.ProcessDefinitionCacheEntry;
import org.activiti.engine.impl.persistence.entity.HistoricVariableInstanceEntityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ExecutionQuery;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import java.util.*;
import java.util.stream.Collectors;

import static timing.ukulele.flow.extention.UserTaskExtensionElementProperty.elememt;

/**
 * 任务相关接口
 */
@RestController
@RequestMapping("/task")
@Api(tags = "任务相关接口")
@Slf4j
public class TaskController {

    @Autowired
    private FlowUserInfoService flowUserInfoService;

    private final TaskService taskService;
    private final ProcessEngine processEngine;
    /**
     * 任务相关操作
     */
    private final TaskRuntime taskRuntime;
    private final CustomTaskRuntime customTaskRuntime;
    private final HistoryService historyService;
    private final RuntimeService runtimeService;
    private final RepositoryService repositoryService;
    private final OperateTaskService operateTaskService;
    private final ProcessHistoryManager processHistoryManager;
    private final ProcessInstanceManager processInstanceManager;

    public TaskController(TaskService taskService, ProcessEngine processEngine, TaskRuntime taskRuntime,
                          CustomTaskRuntime customTaskRuntime, HistoryService historyService, RuntimeService runtimeService,
                          RepositoryService repositoryService, OperateTaskService operateTaskService, ProcessHistoryManager processHistoryManager,
                          ProcessInstanceManager processInstanceManager) {
        this.taskService = taskService;
        this.processEngine = processEngine;
        this.taskRuntime = taskRuntime;
        this.customTaskRuntime = customTaskRuntime;
        this.historyService = historyService;
        this.runtimeService = runtimeService;
        this.repositoryService = repositoryService;
        this.operateTaskService = operateTaskService;
        this.processHistoryManager = processHistoryManager;
        this.processInstanceManager = processInstanceManager;
    }

    @GetMapping("/getTasksByProcessInstanceId/{tenantId}/{processInstanceId}")
    @ApiOperation("根据流程实例id查看已办任务和待办任务以及任务变量")
    public ResponseResult getTasksByProcessInstanceId(
            @ApiParam(value = "系统id", required = true) @PathVariable("tenantId") String tenantId,
            @ApiParam(value = "流程实例id", required = true) @PathVariable("processInstanceId") String processInstanceId) {
        List<TaskVO> listTotal = new ArrayList<>();
        HistoricTaskInstanceQuery historicTaskInstanceQuery;
        historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
                .taskTenantId(tenantId)
                .processInstanceId(processInstanceId);
        List<HistoricTaskInstance> historicTaskInstances = historicTaskInstanceQuery.list();
        if (!CollectionUtils.isEmpty(historicTaskInstances)) {
            for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) {
                TaskVO vo = new TaskVO();
                BeanUtils.copyProperties(historicTaskInstance, vo);
                vo.setProperties(findRunningTaskParams(historicTaskInstance.getProcessDefinitionId(), historicTaskInstance.getTaskDefinitionKey()));
                List<HistoricVariableInstance> historicVariableInstances =
                        historyService.createHistoricVariableInstanceQuery()
                                .taskId(historicTaskInstance.getId())
                                .list();
                if (!CollectionUtils.isEmpty(historicVariableInstances)) {
                    List<HistoricVariableInstanceEntityImpl> historicTaskVariables = new ArrayList<>();
                    for (HistoricVariableInstance historicVariableInstance : historicVariableInstances) {
                        historicTaskVariables.add(
                                (HistoricVariableInstanceEntityImpl) historicVariableInstance);
                    }
                    vo.setHistoryVariables(historicTaskVariables);
                }
                if (historicTaskInstance.getEndTime() != null) {
                    vo.setTaskType(1);
                } else {
                    vo.setTaskType(0);
                }
                listTotal.add(vo);
            }
        }
        return ResponseResult.success(listTotal);
    }

    @PostMapping(path = "returnOrTransferTask")
    @ApiOperation(value = "根据taskId任务转接", notes = "根据taskId任务转接，参数必传taskId(任务id)，assignee(任务接收者)。")
    public ResponseResult returnOrTransferTask(
            @ApiParam(value = "任务id", required = true) @RequestParam("taskId") String taskId,
            @ApiParam(value = "任务接收者,多人用英文逗号隔开") @RequestParam(value = "assignee", required = false) String assignee,
            @ApiParam(value = "企业id") @RequestParam(value = "uuid", required = false) String uuid,
            @RequestParam(value = "departs", required = false) String departs,
            @RequestParam(value = "areacode", required = false) String areacode,
            @RequestParam(value = "roles", required = false) String roles,
            @RequestParam(value = "isand", required = false) String isand,
            @RequestParam(value = "usertype", required = false) String usertype,
            @RequestParam(value = "rulecode", required = false) String rulecode,
            @RequestParam(value = "userpara", required = false) String userpara) {
        try {
            if (StringUtils.isEmpty(taskId)) {
                return ResponseResult.error("参数taskId必须传值!");
            }
            String[] split;
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (!StringUtils.isEmpty(assignee)) {
                split = assignee.split(",");
                if (task != null) {
                    if (StringUtils.isEmpty(task.getAssignee())) {
                        List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(task.getId());
                        if (!CollectionUtils.isEmpty(identityLinks)) {
                            for (IdentityLink identityLink : identityLinks) {
                                taskService.deleteCandidateUser(taskId, identityLink.getUserId());
                            }
                        }
                        if (split.length == 1) {
                            taskService.setAssignee(taskId, split[0]);
                        } else {
                            taskService.setAssignee(taskId, null);
                            for (String candidateUser : split) {
                                taskService.addCandidateUser(taskId, candidateUser);
                            }
                        }
                    } else {
                        if (split.length == 1) {
                            taskService.setAssignee(taskId, split[0]);
                        } else {
                            taskService.setAssignee(taskId, null);
                            for (String candidateUser : split) {
                                taskService.addCandidateUser(taskId, candidateUser);
                            }
                        }
                    }
                } else {
                    return ResponseResult.error("转接任务不存在!请核对taskId!");
                }
            } else if (!StringUtils.isEmpty(uuid) || !StringUtils.isEmpty(departs) || !StringUtils.isEmpty(areacode)
                    || !StringUtils.isEmpty(roles) || !StringUtils.isEmpty(isand) || !StringUtils.isEmpty(usertype)
                    || !StringUtils.isEmpty(rulecode) || !StringUtils.isEmpty(userpara)) {
                List<UserVO> users =
                        flowUserInfoService.getUserList(userpara, uuid, departs, areacode, roles, isand, usertype, null,
                                null, rulecode);
                if (!CollectionUtils.isEmpty(users)) {
                    if (users.size() > 1) {
                        List<String> candidateUsers =
                                users.stream().map(UserVO::getUsername).collect(Collectors.toList());
                        for (String candidateUser : candidateUsers) {
                            taskService.addCandidateUser(taskId, candidateUser);
                        }
                    } else {
                        taskService.setAssignee(taskId, users.get(0).getUsername());
                    }
                } else {
                    throw new NoUserException("查询接收者参数未查到相关人员!");
                }
            } else {
                return ResponseResult.error("任务转接失败,请传入接收者或者查询接收者的相关参数!");
            }
            taskService.setAssignee(taskId, assignee);
            return ResponseResult.success("任务转接成功!");
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseResult.error("任务转接失败:" + e.getMessage());
        }
    }

    @PostMapping(path = "claimTask")
    @ApiOperation(value = "根据taskId拾取任务", notes = "根据taskId拾取任务，对于组任务让指定候选人拾取该任务，参数必传taskId(任务id)，candidateUser(拾取者)")
    public ResponseResult claimTask(@ApiParam(value = "任务id", required = true) @RequestParam("taskId") String taskId,
                                    @ApiParam(value = "拾取任务的候选人", required = true) @RequestParam("candidateUser") String candidateUser) {
        try {
            if (StringUtils.isEmpty(taskId) || StringUtils.isEmpty(candidateUser)) {
                return ResponseResult.error("参数taskId和candidateUser都必须传值!");
            }
            taskService.claim(taskId, candidateUser);
            return ResponseResult.success("拾取任务成功");
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseResult.error("拾取任务失败:" + e.getMessage());
        }
    }

    /**
     * 已测，正常
     */
    @PostMapping(path = "findTaskByAssignee")
    @ApiOperation(value = "根据流程assignee查询当前人的个人任务", notes = "根据流程assignee查询当前人的个人任务")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "assignee", value = "代理人（当前用户）", dataType = "String", paramType = "query", example = ""),
    })
    public ResponseResult findTaskByAssignee(@RequestParam("assignee") String assignee) {

        //创建任务查询对象
        List<Task> taskList;
        try {
            taskList = taskService.createTaskQuery()
                    //指定个人任务查询
                    .taskAssignee(assignee)
                    .list();
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseResult.error("查询失败：" + e.getMessage());
        }

        if (taskList != null && taskList.size() > 0) {
            List<Map<String, String>> resultList = new ArrayList<>();
            for (Task task : taskList) {
                Map<String, String> resultMap = new HashMap<>();
                /* 任务ID */
                resultMap.put("taskID", task.getId());
                /* 任务名称 */
                resultMap.put("taskName", task.getName());
                /* 任务的创建时间 */
                resultMap.put("taskCreateTime", task.getCreateTime().toString());
                /* 任务的办理人 */
                resultMap.put("taskAssignee", task.getAssignee());
                /* 流程实例ID */
                resultMap.put("processInstanceId", task.getProcessInstanceId());
                /* 执行对象ID */
                resultMap.put("executionId", task.getExecutionId());
                /* 流程定义ID */
                resultMap.put("processDefinitionId", task.getProcessDefinitionId());
                resultList.add(resultMap);
            }
            return ResponseResult.success(resultList);
        } else {
            return ResponseResult.success(null);
        }
    }

    @PostMapping(path = "completeTask")
    @ApiOperation(value = "完成任务, taskId为下个待执行任务的id", notes = "完成任务，任务进入下一个节点")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "taskId", value = "任务ID", dataType = "String", paramType = "query", example = ""),
            @ApiImplicitParam(name = "procInstId", value = "流程实例ID", dataType = "String", paramType = "query", example = ""),
            @ApiImplicitParam(name = "days", value = "请假天数", dataType = "Integer", paramType = "query", example = "0"),
    })
    public ResponseResult completeTask(@RequestParam("taskId") String taskId,
                                       @RequestParam("procInstId") String procInstId,
                                       @RequestParam("days") Integer days
                                       // @ApiParam("部门编码") @RequestParam(value = "depcode", required = false) String depcode,
                                       // @ApiParam("区域编码") @RequestParam(value = "areacode", required = false) String areacode,
                                       // @ApiParam("角色名称（逗号隔开）") @RequestParam(value = "roles", required = false) String roles,
                                       // @ApiParam("角色是否是与的关系（1:是，0：否）") @RequestParam(value = "isand", required = false) String isand,
                                       // @ApiParam("用户类型（1:政府,2:企业）") @RequestParam(value = "usertype", required = false) String usertype,
                                       // @ApiParam("流程启动用户loginame") @RequestParam(value = "startuser", required = false) String startuser,
                                       // @ApiParam("流程当前用户loginame") @RequestParam(value = "flowuser", required = false) String flowuser,
                                       // @ApiParam("规则") @RequestParam(value = "rulecode", required = false) String rulecode
    ) {

        try {
            HashMap<String, Object> variables = new HashMap<>(2);
            variables.put("days", days);
            variables.put("agree", 2);
            variables.put("assignee", "timing");
            taskService.complete(taskId, variables);
            //执行完当前步骤后，再通过流程实例id获得下个节点信息
            List<Task> task = processEngine.getTaskService()
                    .createTaskQuery()
                    .processInstanceId(procInstId).list();
            for (Task task1 : task) {
                task1.setAssignee("timing");
                processEngine.getTaskService().saveTask(task1);
                taskId = task1.getId();
                // List<IdentityLink> IdentityLinks = processEngine.getTaskService().getIdentityLinksForTask(task1.getId());
                // for (IdentityLink identityLink : IdentityLinks) {
                //     identityLink.getUserId();
                // }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseResult.error("提交失败:" + e.getMessage());
        }
        return ResponseResult.success(taskId);
    }

    // /**
    //  *
    //  * securityUtil.logInAs(assignee)有问题
    //  */
    // @PostMapping(path = "/completeTaskByAssignee")
    // @ApiOperation(value = "完成指派人所有任务", notes = "完成指派人所有任务")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "assignee", value = "指派人", dataType = "String", paramType = "query", example = "")
    //                    })
    // public ResponseResult completeTaskByAssignee(@RequestParam("assignee") String assignee) {
    //     try {
    //         ActivitiUtil.completeTask(assignee);
    //         return ResponseResult.success("完成指派人所有任务成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("完成指派人所有任务失败");
    // }

    // @PostMapping(path = "/completeTaskByKey")
    // @ApiOperation(value = "完成指派人当前业务key对应的任务", notes = "完成指派人当前业务key对应的任务")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "tenantId", value = "租户id", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "assignee", value = "指派人", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "businessKey", value = "任务key", dataType = "String", paramType = "query", example = "")})
    // public ResponseResult completeTaskByKey(@RequestParam("assignee") String assignee,
    //                                         @RequestParam("businessKey") String businessKey,
    //                                         @RequestParam("tenantId") String tenantId) {
    //     try {
    //         ActivitiUtil.completeTask(assignee, businessKey, tenantId);
    //         return ResponseResult.success("完成指派人当前业务key对应的任务成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("完成指派人当前业务key对应的任务失败");
    // }

    // @PostMapping(path = "/completeTaskWithVariables")
    // @ApiOperation(value = "根据变量完成任务", notes = "根据变量完成任务")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "assignee", value = "指派人", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "variables", value = "map的变量", dataType = "Map", paramType = "query")})
    // public ResponseResult completeTaskWithVariables(@RequestParam("assignee") String assignee, @RequestParam("variables") HashMap<String, Object> variables) {
    //     try {
    //         ActivitiUtil.completeTaskWithVariables(assignee, variables);
    //         return ResponseResult.success("根据变量完成任务成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("根据变量完成任务失败");
    // }

    // @PostMapping(path = "/completeTaskWithGroup")
    // @ApiOperation(value = "候选人拾取并完成任务", notes = "候选人拾取并完成任务")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "assignee", value = "指派人", dataType = "String", paramType = "query", example = "")})
    // public ResponseResult completeTaskWithGroup(@RequestParam("assignee") String assignee) {
    //     try {
    //         ActivitiUtil.completeTaskWithGroup(assignee);
    //         return ResponseResult.success("候选人拾取并完成任务成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("候选人拾取并完成任务失败");
    // }

    // @PostMapping(path = "/completeTaskWithGroupWithVariables")
    // @ApiOperation(value = "候选人拾取并完成任务并指定变量", notes = "候选人拾取并完成任务并指定变量")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "assignee", value = "指派人", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "variables", value = "map的变量", dataType = "Map", paramType = "query")})
    // public ResponseResult completeTaskWithGroupWithVariables(@RequestParam("assignee") String assignee, @RequestParam("variables") HashMap<String, Object> variables) {
    //     try {
    //         ActivitiUtil.completeTaskWithGroupWithVariables(assignee, variables);
    //         return ResponseResult.success("候选人拾取并完成任务并指定变量成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("候选人拾取并完成任务并指定变量失败");
    // }

    // @PostMapping(path = "/printTaskList")
    // @ApiOperation(value = "打印指派人所有任务", notes = "打印指派人所有任务")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "assignee", value = "指派人", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "startNum", value = "分页开始下标", dataType = "Integer", paramType = "query"),
    //                        @ApiImplicitParam(name = "endNum", value = "分页结束下标", dataType = "Integer", paramType = "query")})
    // public ResponseResult printTaskList(@RequestParam("assignee") String assignee,
    //                                     @RequestParam("startNum") Integer startNum,
    //                                     @RequestParam("endNum") Integer endNum) {
    //     try {
    //         ActivitiUtil.printTaskList(assignee, startNum, endNum);
    //         return ResponseResult.success("打印指派人所有任务成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("打印指派人所有任务失败");
    // }

    // @PostMapping(path = "/getTaskList")
    // @ApiOperation(value = "查询当前指派人的任务", notes = "查询当前指派人的任务")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "assignee", value = "指派人", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "startNum", value = "分页开始下标", dataType = "Integer", paramType = "query"),
    //                        @ApiImplicitParam(name = "endNum", value = "分页结束下标", dataType = "Integer", paramType = "query")})
    // public ResponseResult getTaskList(@RequestParam("assignee") String assignee,
    //                                   @RequestParam("startNum") Integer startNum,
    //                                   @RequestParam("endNum") Integer endNum) {
    //     try {
    //         Page<org.activiti.api.task.model.Task> page = ActivitiUtil.getTaskList(assignee, startNum, endNum);
    //         return ResponseResult.success(page);
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("查询当前指派人的任务失败");
    // }

    // @PostMapping(path = "/getTaskListByKey")
    // @ApiOperation(value = "查询当前指派人当前业务Key对应的流程实例中的任务", notes = "查询当前指派人当前业务Key对应的流程实例中的任务")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "assignee", value = "指派人", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "businessKey", value = "业务key", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "startNum", value = "分页开始下标", dataType = "Integer", paramType = "query"),
    //                        @ApiImplicitParam(name = "endNum", value = "分页结束下标", dataType = "Integer", paramType = "query")})
    // public ResponseResult getTaskListByKey(@RequestParam("assignee") String assignee,
    //                                      @RequestParam("businessKey") String businessKey,
    //                                      @RequestParam("startNum") Integer startNum,
    //                                      @RequestParam("endNum") Integer endNum) {
    //     try {
    //         List<Task> list = ActivitiUtil.getTaskList(assignee, businessKey, startNum, endNum);
    //         return ResponseResult.success(list);
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("查询当前指派人当前业务Key对应的流程实例中的任务失败");
    // }

    // @PostMapping(path = "/getSingleTask")
    // @ApiOperation(value = "查询当前指派人当前业务Key对应的流程实例中的唯一任务", notes = "查询当前指派人当前业务Key对应的流程实例中的任务，某一时间内一个业务key对应的指派人的任务应该是唯一的")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "tenantId", value = "租户id", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "assignee", value = "指派人", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "businessKey", value = "map的变量", dataType = "Map", paramType = "query")})
    // public ResponseResult getSingleTask(@RequestParam("assignee") String assignee,
    //                                     @RequestParam("businessKey") String businessKey,
    //                                     @RequestParam("tenantId") String tenantId) {
    //     try {
    //         Task singleTask = ActivitiUtil.getTask(assignee, businessKey, tenantId);
    //         return ResponseResult.success(singleTask);
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("查询当前指派人当前业务Key对应的流程实例中的唯一任务失败");
    // }
    //todo
    // @PostMapping(path = "/auditByCandidate")
    // @ApiOperation(value = "审核(candidate user的场合)", notes = "审核(candidate user的场合)")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "tenantId", value = "租户id", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "assignee", value = "执行人", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "auditFlg", value = "审核flg, true：通过，false:驳回", dataType = "Boolean", paramType = "query", example = "true"),
    //                        @ApiImplicitParam(name = "variables", value = "完成任务时带上变量集合", dataType = "Map", paramType = "query")})
    // public ResponseResult auditByCandidate(@RequestParam("assignee") String assignee,
    //                                        @RequestParam("auditFlg") Boolean auditFlg,
    //                                        @RequestParam("variables") HashMap<String, Object> variables,
    //                                        @RequestParam("tenantId") String tenantId) {
    //     try {
    //         ActivitiUtil.auditByCandidate(tenantId, assignee, auditFlg, variables);
    //         return ResponseResult.success("审核成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("审核失败");
    // }
    //
    // @PostMapping(path = "/claimTask")
    // @ApiOperation(value = "拾取任务", notes = "拾取任务")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "assignee", value = "指派人", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "taskId", value = "taskId", dataType = "String", paramType = "query", example = "")})
    // public ResponseResult claimTask(@RequestParam("assignee") String assignee, @RequestParam("taskId") String taskId) {
    //     try {
    //         ActivitiUtil.claimTask(assignee, taskId);
    //         return ResponseResult.success("拾取任务成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("拾取任务失败");
    // }
    //
    // @PostMapping(path = "/transferTask")
    // @ApiOperation(value = "将任务指派给其它人", notes = "将任务指派给其它人")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "taskId", value = "taskId", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "assigneeOther", value = "其它人", dataType = "String", paramType = "query", example = "")})
    // public ResponseResult transferTask(@RequestParam("taskId") String taskId, @RequestParam("assigneeOther") String assigneeOther) {
    //     try {
    //         ActivitiUtil.transferTask(taskId, assigneeOther);
    //         return ResponseResult.success("将任务指派给其它人成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("将任务指派给其它人失败");
    // }

    /**
     * 已测
     *
     * @param processInstanceId
     * @return
     */
    @PostMapping(path = "/getHistoryTaskList")
    @ApiOperation(value = "获取历史任务", notes = "根据流程Id获取历史任务")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "tenantId", value = "租户id", dataType = "String", paramType = "query", example = ""),
            @ApiImplicitParam(name = "processInstanceId", value = "流程实例Id", dataType = "String", paramType = "query", example = "")})
    public ResponseResult getHistoryTaskList(@RequestParam("processInstanceId") String processInstanceId,
                                             @RequestParam("tenantId") String tenantId) {
        try {
            List<HistoricTaskInstance> list = ActivitiUtil.getHistoryTaskList(processInstanceId, tenantId);
            return ResponseResult.success(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseResult.error("根据流程Id获取历史任务失败");
    }

    @PostMapping(path = "/getAssigneeHistoryTaskList")
    @ApiOperation(value = "获取历史任务", notes = "根据执行人assignee获取历史任务")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "tenantId", value = "租户id", dataType = "String", paramType = "query", example = ""),
            @ApiImplicitParam(name = "assignee", value = "执行人", dataType = "String", paramType = "query", example = "")})
    public ResponseResult getAssigneeHistoryTaskList(@RequestParam("assignee") String assignee,
                                                     @RequestParam("tenantId") String tenantId) {
        try {
            List<HistoricTaskInstance> list = ActivitiUtil.getAssigneeHistoryTaskList(assignee, tenantId);
            return ResponseResult.success(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseResult.error("根据执行人assignee获取历史任务失败");
    }

    // @PostMapping(path = "/createTask")
    // @ApiOperation(value = "创建任务,指定执行人", notes = "创建任务,指定执行人,注意这个任务不会影响整个流程的进行")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "tenantId", value = "租户id", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "assignee", value = "登录用户", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "taskName", value = "任务名", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "assigneeNewTask", value = "执行人", dataType = "String", paramType = "query", example = "")})
    // public ResponseResult createTask(
    //                                  @RequestParam("tenantId") String tenantId,
    //                                  @RequestParam("assignee") String assignee,
    //                                  @RequestParam("taskName") String taskName,
    //                                  @RequestParam("assigneeNewTask") String assigneeNewTask) {
    //     try {
    //         org.activiti.api.task.model.Task task = ActivitiUtil.createTask(tenantId, assignee, taskName, assigneeNewTask);
    //         return ResponseResult.success(task);
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("创建任务,指定执行人失败");
    // }
    //
    // @PostMapping(path = "/createSubTask")
    // @ApiOperation(value = "创建子任务,指定执行人", notes = "创建子任务,指定执行人,注意这个任务不会影响整个流程的进行")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "assignee", value = "登录用户", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "parentTaskId", value = "父任务Id", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "assigneeNewTask", value = "执行人", dataType = "String", paramType = "query", example = "")})
    // public ResponseResult createSubTask(@RequestParam("assignee") String assignee,
    //     @RequestParam("parentTaskId") String parentTaskId,
    //     @RequestParam("assigneeNewTask") String assigneeNewTask) {
    //     try {
    //         ActivitiUtil.createSubTask(assignee, parentTaskId, assigneeNewTask);
    //         return ResponseResult.success("创建子任务,指定执行人成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("创建子任务,指定执行人失败");
    // }

    // @PostMapping(path = "/getAllNode")
    // @ApiOperation(value = "获取所有任务节点", notes = "获取所有任务节点")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "processDefinitionId", value = "登录用户", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "processInstanceId", value = "父任务Id", dataType = "String", paramType = "query", example = ""),
    //                        @ApiImplicitParam(name = "activityId", value = "执行人", dataType = "String", paramType = "query", example = "")})
    // public ResponseResult getAllNode(@RequestParam("processDefinitionId") String processDefinitionId,
    //     @RequestParam("processInstanceId") String processInstanceId,
    //     @RequestParam("activityId") String activityId) {
    //     try {
    //         ActivitiUtil.getAllNode(processDefinitionId, processInstanceId, activityId);
    //         return ResponseResult.error("创建子任务,指定执行人成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("创建子任务,指定执行人失败");
    // }

    // @PostMapping(path = "/jumpTask")
    // @ApiOperation(value = "跳转任务", notes = "跳转任务")
    // @ApiImplicitParams({
    //                        @ApiImplicitParam(name = "assignee", value = "登录用户", dataType = "String", paramType = "query", example = "")})
    // public ResponseResult jumpTask(@RequestParam("assignee") String assignee) {
    //     try {
    //         ActivitiUtil.jumpTask(assignee);
    //         return ResponseResult.success("跳转任务成功");
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return ResponseResult.error("跳转任务失败");
    // }

    /**
     * 在comment处尝试加tenantId，还未试
     */
    @PostMapping(path = "/addComment")
    @ApiOperation(value = "添加comment", notes = "添加comment")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "tenantId", value = "租户id", dataType = "String", paramType = "query", example = ""),
            @ApiImplicitParam(name = "username", value = "用户名", dataType = "String", paramType = "query", example = ""),
            @ApiImplicitParam(name = "taskId", value = "任务Id", dataType = "String", paramType = "query", example = ""),
            @ApiImplicitParam(name = "comment", value = "comment", dataType = "String", paramType = "query", example = "")})
    public ResponseResult addComment(
            @RequestParam("tenantId") String tenantId,
            @RequestParam("username") String username,
            @RequestParam("taskId") String taskId,
            @RequestParam("comment") String comment) {
        try {
            ActivitiUtil.addComment(tenantId, username, taskId, comment);
            return ResponseResult.success("添加comment成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseResult.error("添加comment失败");
    }

    @PostMapping(path = "/getComment")
    @ApiOperation(value = "获取comment", notes = "获取comment")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "tenantId", value = "租户id", dataType = "String", paramType = "query", example = ""),
            @ApiImplicitParam(name = "username", value = "用户名", dataType = "String", paramType = "query", example = ""),
            @ApiImplicitParam(name = "taskId", value = "任务Id", dataType = "String", paramType = "query", example = "")})
    public ResponseResult getComment(
            @RequestParam("tenantId") String tenantId,
            @RequestParam("username") String username,
            @RequestParam("taskId") String taskId) {
        try {
            List<Comment> list = taskService.getTaskComments(tenantId, taskId);
            return ResponseResult.success(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseResult.error("获取comment失败");
    }


    /**
     * 退回到上一节点
     *
     * @param task 当前任务
     */
    public void backProcess(org.activiti.api.task.model.Task task) throws Exception {

        String processInstanceId = task.getProcessInstanceId();

        // 取得所有历史任务按时间降序排序
        List<HistoricTaskInstance> htiList = getPublicHistoryTaskList(processInstanceId);

        int size = 2;

        if (ObjectUtils.isEmpty(htiList) || htiList.size() < size) {
            return;
        }

        // list里的第二条代表上一个任务
        HistoricTaskInstance lastTask = htiList.get(1);

        // list里第一条代表当前任务
        HistoricTaskInstance curTask = htiList.get(0);

        // 当前节点的executionId
        String curExecutionId = curTask.getExecutionId();


        // 上个节点的taskId
        String lastTaskId = lastTask.getId();
        // 上个节点的executionId
        String lastExecutionId = lastTask.getExecutionId();

        if (null == lastTaskId) {
            throw new Exception("LAST TASK IS NULL");
        }

        String processDefinitionId = lastTask.getProcessDefinitionId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

        String lastActivityId = null;
        List<HistoricActivityInstance> haiFinishedList = historyService.createHistoricActivityInstanceQuery()
                .executionId(lastExecutionId).finished().list();

        for (HistoricActivityInstance hai : haiFinishedList) {
            if (lastTaskId.equals(hai.getTaskId())) {
                // 得到ActivityId，只有HistoricActivityInstance对象里才有此方法
                lastActivityId = hai.getActivityId();
                break;
            }
        }

        // 得到上个节点的信息
        FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivityId);

        // 取得当前节点的信息
        Execution execution = runtimeService.createExecutionQuery().executionId(curExecutionId).singleResult();
        String curActivityId = execution.getActivityId();
        FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(curActivityId);

        //记录当前节点的原活动方向
        List<SequenceFlow> oriSequenceFlows = new ArrayList<>(curFlowNode.getOutgoingFlows());

        //清理活动方向
        curFlowNode.getOutgoingFlows().clear();

        //建立新方向
        List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(curFlowNode);
        newSequenceFlow.setTargetFlowElement(lastFlowNode);
        newSequenceFlowList.add(newSequenceFlow);
        curFlowNode.setOutgoingFlows(newSequenceFlowList);

        // 完成任务
        taskService.complete(task.getId());

        //恢复原方向
        curFlowNode.setOutgoingFlows(oriSequenceFlows);

        Task nextTask = taskService
                .createTaskQuery().processInstanceId(processInstanceId).singleResult();

        // 设置执行人
        if (nextTask != null) {
            taskService.setAssignee(nextTask.getId(), lastTask.getAssignee());
        }
    }

    /**
     * 动态增加任务
     *
     * @param task     当前任务
     * @param assignee 增加任务的指派人
     */
    public void addTask(Task task, String assignee) {
        String processInstanceId = task.getProcessInstanceId();

        // 取得所有历史任务按时间降序排序
        List<HistoricTaskInstance> htiList = getPublicHistoryTaskList(processInstanceId);

        int size = 2;

        if (ObjectUtils.isEmpty(htiList) || htiList.size() < size) {
            return;
        }

        // list里第一条代表当前任务
        HistoricTaskInstance curTask = htiList.get(0);

        // 当前节点的executionId
        String curExecutionId = curTask.getExecutionId();

        String processDefinitionId = task.getProcessDefinitionId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

        // 取得当前节点的信息
        Execution execution = runtimeService.createExecutionQuery().executionId(curExecutionId).singleResult();
        String curActivityId = execution.getActivityId();
        FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(curActivityId);

        //记录当前节点的原活动方向
        List<SequenceFlow> oriSequenceFlows = new ArrayList<>(curFlowNode.getOutgoingFlows());

        //清理活动方向
        curFlowNode.getOutgoingFlows().clear();


        // 创建新节点
        UserTask newUserTask = new UserTask();
        newUserTask.setId("destinyD");
        newUserTask.setName("加签节点 destinyD");
        newUserTask.setAssignee(assignee);

        // 设置新节点的出线为当前节点的出线
        newUserTask.setOutgoingFlows(oriSequenceFlows);

        // 当前节点与新节点的连线
        SequenceFlow sequenceFlow = new SequenceFlow();
        sequenceFlow.setId("extra");
        sequenceFlow.setSourceFlowElement(curFlowNode);
        sequenceFlow.setTargetFlowElement(newUserTask);

        // 将当前节点的出线设置为指向新节点
        curFlowNode.setOutgoingFlows(Collections.singletonList(sequenceFlow));

        // 取得流程定义缓存
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration();
        ProcessDefinitionCacheEntry cacheEntry = processEngineConfiguration.getProcessDefinitionCache().get(processDefinitionId);

        // 从缓存中取得process对象
        Process process = cacheEntry.getProcess();
        // 添加新节点到process中
        process.addFlowElement(newUserTask);
        // 添加新连线到process中
        process.addFlowElement(sequenceFlow);

        // 更新缓存
        cacheEntry.setProcess(process);

        //        // 完成任务
        //        activitiUtil.taskService.complete(task.getId());
        //        System.out.println("完成任务");

        //        // 取得managementService
        //        ManagementService managementService = processEngine.getManagementService();
        //
        //        // 立即生效
        //        managementService.executeCommand(new JumpCmd(task.getId(), newUserTask.getId()));

        System.out.println("加签成功");


        //        FlowElement nextUserFlowElement = getNextUserFlowElement(task);
        //        System.out.println("下个任务为：" + nextUserFlowElement.getName());
    }

    /**
     * 获取当前任务节点的下一个任务节点
     *
     * @param task 当前任务节点
     * @return 下个任务节点
     * @throws Exception
     */
    public FlowElement getNextUserFlowElement(org.activiti.api.task.model.Task task) {
        // 取得已提交的任务
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery()
                .taskId(task.getId()).singleResult();

        // 获得流程定义
        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(historicTaskInstance.getProcessDefinitionId());

        //获得当前流程的活动ID
        ExecutionQuery executionQuery = runtimeService.createExecutionQuery();
        Execution execution = executionQuery.executionId(historicTaskInstance.getExecutionId()).singleResult();
        String activityId = execution.getActivityId();
        UserTask userTask = null;
        while (true) {
            //根据活动节点获取当前的组件信息
            FlowNode flowNode = getFlowNode(processDefinition.getId(), activityId);
            //获取该节点之后的流向
            List<SequenceFlow> sequenceFlowListOutGoing = flowNode.getOutgoingFlows();

            // 获取的下个节点不一定是userTask的任务节点，所以要判断是否是任务节点
            if (sequenceFlowListOutGoing.size() > 1) {
                // 如果有1条以上的出线，表示有分支，需要判断分支的条件才能知道走哪个分支
                // 遍历节点的出线得到下个activityId
                activityId = getNextActivityId(execution.getId(),
                        task.getProcessInstanceId(), sequenceFlowListOutGoing);
            } else if (sequenceFlowListOutGoing.size() == 1) {
                // 只有1条出线,直接取得下个节点
                SequenceFlow sequenceFlow = sequenceFlowListOutGoing.get(0);
                // 下个节点
                FlowElement flowElement = sequenceFlow.getTargetFlowElement();
                if (flowElement instanceof UserTask) {
                    // 下个节点为UserTask时
                    userTask = (UserTask) flowElement;
                    System.out.println("下个任务为:" + userTask.getName());
                    return userTask;
                } else if (flowElement instanceof ExclusiveGateway) {
                    // 下个节点为排它网关时
                    ExclusiveGateway exclusiveGateway = (ExclusiveGateway) flowElement;
                    List<SequenceFlow> outgoingFlows = exclusiveGateway.getOutgoingFlows();
                    // 遍历网关的出线得到下个activityId
                    activityId = getNextActivityId(execution.getId(), task.getProcessInstanceId(), outgoingFlows);
                }

            } else {
                // 没有出线，则表明是结束节点
                return null;
            }
        }

    }

    /**
     * 查询当前指派人的任务
     *
     * @param assignee 指派人
     * @param startNum 分页开始下标
     * @param endNum   分页结束下标
     * @return 任务list
     */
    public Page<org.activiti.api.task.model.Task> getPublicTaskList(String assignee, Integer startNum, Integer endNum) {
        return customTaskRuntime.tasks(Pageable.of(startNum, endNum));
    }

    /**
     * 根据活动节点和流程定义ID获取该活动节点的组件信息
     */
    public FlowNode getFlowNode(String processDefinitionId, String flowElementId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(flowElementId);
        return flowNode;
    }

    /**
     * 根据el表达式取得满足条件的下一个activityId
     *
     * @param executionId
     * @param processInstanceId
     * @param outgoingFlows
     * @return
     */
    public String getNextActivityId(String executionId,
                                    String processInstanceId,
                                    List<SequenceFlow> outgoingFlows) {
        String activityId = null;
        // 遍历出线
        for (SequenceFlow outgoingFlow : outgoingFlows) {
            // 取得线上的条件
            String conditionExpression = outgoingFlow.getConditionExpression();
            // 取得所有变量
            Map<String, Object> variables = runtimeService.getVariables(executionId);
            String variableName = "";
            // 判断网关条件里是否包含变量名
            for (String s : variables.keySet()) {
                if (conditionExpression.contains(s)) {
                    // 找到网关条件里的变量名
                    variableName = s;
                }
            }
            String conditionVal = getVariableValue(variableName, processInstanceId);
            // 判断el表达式是否成立
            if (isCondition(variableName, conditionExpression, conditionVal)) {
                // 取得目标节点
                FlowElement targetFlowElement = outgoingFlow.getTargetFlowElement();
                activityId = targetFlowElement.getId();
            }
        }
        return activityId;
    }

    /**
     * 根据id获取任务
     *
     * @param taskId 任务id
     * @return Task
     */
    public Task getTaskById(String taskId) {
        return taskService.createTaskQuery().taskId(taskId).singleResult();
    }

    public List<HistoricTaskInstance> getPublicHistoryTaskList(String processInstanceId) {
        return historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByTaskCreateTime()
                .desc()
                .list();
    }

    /**
     * 取得流程变量的值
     *
     * @param variableName      变量名
     * @param processInstanceId 流程实例Id
     * @return
     */
    public String getVariableValue(String variableName, String processInstanceId) {
        Execution execution = runtimeService
                .createExecutionQuery().processInstanceId(processInstanceId).list().get(0);
        Object object = runtimeService.getVariable(execution.getId(), variableName);
        return object == null ? "" : object.toString();
    }

    /**
     * 根据key和value判断el表达式是否通过
     *
     * @param key   el表达式key
     * @param el    el表达式
     * @param value el表达式传入值
     * @return
     */
    public static boolean isCondition(String key, String el, String value) {
        ExpressionFactory factory = new ExpressionFactoryImpl();
        SimpleContext context = new SimpleContext();
        context.setVariable(key, factory.createValueExpression(value, String.class));
        ValueExpression e = factory.createValueExpression(context, el, boolean.class);
        return (Boolean) e.getValue(context);
    }


    /**
     * 获取用户正在运行任务的自定义参数
     *
     * @param processDefinitionId
     * @param taskDefinitionKey
     * @return
     */
    public Map<String, String> findRunningTaskParams(String processDefinitionId, String taskDefinitionKey) {
        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinitionId);
        // 获得流程定义
        FlowElement flowElement = bpmnModel.getMainProcess().getFlowElement(taskDefinitionKey);
        if (flowElement == null) {
            return null;
        }
        if (!(flowElement instanceof UserTask)) {
            return null;
        }
        UserTask userTask = (UserTask) flowElement;
        //
        Map<String, String> property = new HashMap<>();
        //解析
        Map<String, List<ExtensionElement>> customerProperties = userTask.getExtensionElements();
        if (!CollectionUtils.isEmpty(customerProperties) && customerProperties.containsKey(elememt)) {
            ExtensionElement e = customerProperties.get(elememt).get(0);
            Map<String, List<ExtensionAttribute>> attributes = e.getAttributes();
            attributes.forEach((key, attr) ->
            {
                for (ExtensionAttribute extensionAttribute : attr) {
                    property.put(extensionAttribute.getName(), extensionAttribute.getValue());
                }
            });
        }
        return property;
    }

}
